package ysm.security;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import com.fasterxml.jackson.databind.ObjectMapper;

import ysm.service.UserService;


@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter{
	@Autowired
	private UserService userService;
	
	@Bean
	PasswordEncoder passwordEncode () {
		return new BCryptPasswordEncoder();
	}
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception{
		auth.userDetailsService(userService);
	}
	
	@Override
	protected void configure (HttpSecurity http) throws Exception {
		http.cors().and().authorizeRequests()
		.antMatchers("/admin/**")
		.hasRole("ADMIN")
		.antMatchers("/user/**")
		.access("hasAnyRole('ADMIN', 'USER')")
		.antMatchers("/db/**")
		.access("hasRole('ADMIN') and hasRole('DBA')")
		.antMatchers("/public/**", "/css/**", "/js/**", "/img/**", "/excel/**").permitAll()
		.anyRequest()
		.authenticated()
		.and()
		.formLogin()
		//.loginPage("/login_page")
		.loginProcessingUrl("/login")
		.usernameParameter("account")
		.passwordParameter("password")
		.successHandler(new AuthenticationSuccessHandler() {
			
			@Override
			public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
					Authentication authentication) throws IOException, ServletException {
				// TODO Auto-generated method stub
				Object pricipal = authentication.getPrincipal();
				response.setContentType("application/json;charset=utf-8");
				PrintWriter out = response.getWriter();
				response.setStatus(200);
				Map<String, Object> map = new HashMap<>();
				map.put("status", 200);
				map.put("msg", pricipal);
				ObjectMapper om = new ObjectMapper();
				out.write(om.writeValueAsString(map));
				out.flush();
				out.close();
			}
		})
		.failureHandler(new AuthenticationFailureHandler() {
			
			@Override
			public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
					AuthenticationException exception) throws IOException, ServletException {
				// TODO Auto-generated method stub
				response.setContentType("application/json;charset=utf-8");
				PrintWriter out = response.getWriter();
				response.setStatus(200);
				Map<String, Object> map = new HashMap<>();
				map.put("status", 401);
				if (exception instanceof LockedException) {
					map.put("msg", "账户被锁定，登陆失败");
				} else if (exception instanceof BadCredentialsException) {
					map.put("msg", "账户名或密码输入错误，登陆失败?");
				} else if (exception instanceof DisabledException) {
					map.put("msg", "账户被禁用，登陆失败");
				} else if (exception instanceof AccountExpiredException) {
					map.put("msg", "账户已过期，登陆失败");
				} else if (exception instanceof CredentialsExpiredException) {
					map.put("msg", "密码过期，登陆失败?");
				} else {
					map.put("msg", "登陆失败");
				}
				
				ObjectMapper om = new ObjectMapper();
				out.write(om.writeValueAsString(map));
				out.flush();
				out.close();
			}
		})
		.permitAll()
		.and()
//		.exceptionHandling().authenticationEntryPoint( macLoginUrlAuthenticationEntryPoint())
		.logout()
		.logoutUrl("/logout")
		.clearAuthentication(true)
		.invalidateHttpSession(true)
		.addLogoutHandler(new LogoutHandler() {
			
			@Override
			public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
				// TODO Auto-generated method stub
				
			}
		})
		.logoutSuccessHandler(new LogoutSuccessHandler() {
			
			@Override
			public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
					throws IOException, ServletException {
				// TODO Auto-generated method stub
				response.sendRedirect("/public/login_page_self");
			}
		})
		.and()
		.csrf()
		.disable()
		.exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint());
	}
	
//	@Bean
//    public AuthenticationEntryPoint macLoginUrlAuthenticationEntryPoint() {
//        return new MacLoginUrlAuthenticationEntryPoint(loginForm.getLoginPageUrl());
//    }

}
